package org.csu.question.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.csu.question.entity.dto.KnowledgePointMastery;
import org.csu.question.entity.dto.KnowledgePointStats;
import org.csu.question.entity.po.AnswerRecord;
import org.csu.question.entity.po.KnowledgePoint;
import org.csu.question.entity.po.Questions;
import org.csu.question.mapper.AnswerRecordMapper;
import org.csu.question.mapper.KnowledgePointMapper;
import org.csu.question.mapper.QuestionMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class QuestionRecommendationService {

    private final AnswerRecordMapper answerRecordMapper;

    private final QuestionMapper questionMapper;

    private final KnowledgePointMapper knowledgePointMapper;

    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 智能推荐题目
     */
    public List<Questions> recommendQuestions(Long userId, Integer count) {
        String cacheKey = "recommend:user:" + userId;

        // 尝试从缓存获取
        List<Questions> cachedQuestions = getCachedRecommendations(cacheKey);
        if (cachedQuestions != null && !cachedQuestions.isEmpty()) {
            return cachedQuestions.stream().limit(count).collect(Collectors.toList());
        }

        // 重新计算推荐
        List<Questions> recommendations = calculateRecommendations(userId, count);

        // 缓存结果（5分钟）
        cacheRecommendations(cacheKey, recommendations, 300);

        return recommendations;
    }

    /**
     * 计算推荐题目
     */
    private List<Questions> calculateRecommendations(Long userId, Integer count) {
        // 1. 获取用户最近30天的答题统计
        LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30);
        List<AnswerRecord> recentRecords = answerRecordMapper.selectRecordsByTimeRange(userId, thirtyDaysAgo);

        // 2. 计算各知识点的掌握情况
        Map<Long, KnowledgePointMastery> masteryMap = calculateMasteryMap(userId, recentRecords);

        // 3. 根据掌握情况选择题目
        return selectQuestionsByMastery(masteryMap, count, userId);
    }

    /**
     * 计算知识点掌握情况
     */
    private Map<Long, KnowledgePointMastery> calculateMasteryMap(Long userId, List<AnswerRecord> recentRecords) {
        Map<Long, KnowledgePointMastery> masteryMap = new HashMap<>();

        // 获取用户所有知识点统计
        List<KnowledgePointStats> stats = answerRecordMapper.selectUserKnowledgePointStats(userId);

        // 获取所有知识点
        List<KnowledgePoint> allKnowledgePoints = knowledgePointMapper.selectList(null);

        for (KnowledgePoint kp : allKnowledgePoints) {
            Long kpId = kp.getId();

            // 查找对应的统计信息
            KnowledgePointStats stat = stats.stream()
                    .filter(s -> s.getKnowledgePointId().equals(kpId))
                    .findFirst()
                    .orElse(null);

            if (stat != null) {
                // 计算最近答题趋势
                List<AnswerRecord> recentKpRecords = answerRecordMapper
                        .selectRecentRecordsByKnowledgePoint(userId, kpId, 5);

                double recentCorrectRate = recentKpRecords.isEmpty() ? 0.0 :
                        recentKpRecords.stream()
                                .mapToDouble(r -> r.getIsCorrect() ? 1.0 : 0.0)
                                .average()
                                .orElse(0.0);

                // 计算推荐权重
                double weight = calculateRecommendWeight(stat.getCorrectRate(), recentCorrectRate,
                        stat.getTotalCount().intValue());

                masteryMap.put(kpId, new KnowledgePointMastery(
                        kpId, kp.getName(), kp.getTag(),
                        stat.getTotalCount().intValue(), stat.getCorrectCount().intValue(),
                        stat.getCorrectRate(), recentCorrectRate, weight
                ));
            } else {
                // 没有答题记录的知识点，给予中等权重
                masteryMap.put(kpId, new KnowledgePointMastery(
                        kpId, kp.getName(), kp.getTag(),
                        0, 0, 0.0, 0.0, 0.6
                ));
            }
        }

        return masteryMap;
    }

    /**
     * 计算推荐权重
     */
    private double calculateRecommendWeight(Double correctRate, Double recentCorrectRate, Integer totalCount) {
        // 综合考虑总体正确率和最近正确率
        double avgCorrectRate = (correctRate * 0.7 + recentCorrectRate * 0.3);

        // 反向权重：正确率越低，推荐权重越高
        double weight = 1.0 - avgCorrectRate;

        // 答题次数修正
        if (totalCount < 3) {
            weight += 0.3; // 答题次数少，增加权重
        } else if (totalCount < 10) {
            weight += 0.1;
        }

        // 权重范围控制
        return Math.max(0.1, Math.min(1.0, weight));
    }

    /**
     * 根据掌握情况选择题目
     */
    private List<Questions> selectQuestionsByMastery(Map<Long, KnowledgePointMastery> masteryMap,
                                                     Integer count, Long userId) {
        List<Questions> recommendedQuestions = new ArrayList<>();

        // 按权重排序
        List<KnowledgePointMastery> sortedMasteries = masteryMap.values().stream()
                .sorted((a, b) -> Double.compare(b.getRecommendWeight(), a.getRecommendWeight()))
                .toList();

        // 为每个知识点分配题目数量
        int totalKnowledgePoints = sortedMasteries.size();
        int baseQuestionPerKp = Math.max(1, count / totalKnowledgePoints);

        for (KnowledgePointMastery mastery : sortedMasteries) {
            if (recommendedQuestions.size() >= count) {
                break;
            }

            // 计算该知识点应推荐的题目数量
            int questionsNeeded = (int) Math.ceil(baseQuestionPerKp * mastery.getRecommendWeight());
            questionsNeeded = Math.min(questionsNeeded, count - recommendedQuestions.size());

            // 获取该知识点的未答题目
            List<Questions> unansweredQuestions = questionMapper
                    .selectUnansweredQuestionsByKnowledgePoint(mastery.getKnowledgePointId(), userId);

            // 随机选择题目
            Collections.shuffle(unansweredQuestions);
            List<Questions> selectedQuestions = unansweredQuestions.stream()
                    .limit(questionsNeeded)
                    .toList();

            recommendedQuestions.addAll(selectedQuestions);
        }

        // 如果题目不够，从所有未答题目中随机补充
        if (recommendedQuestions.size() < count) {
            List<Questions> allUnanswered = questionMapper.selectUnansweredQuestions(userId);
            Collections.shuffle(allUnanswered);

            int needed = count - recommendedQuestions.size();
            List<Questions> additional = allUnanswered.stream()
                    .filter(q -> !recommendedQuestions.contains(q))
                    .limit(needed)
                    .toList();

            recommendedQuestions.addAll(additional);
        }

        // 最终打乱顺序
        Collections.shuffle(recommendedQuestions);
        return recommendedQuestions.stream().limit(count).collect(Collectors.toList());
    }

    /**
     * 缓存推荐结果
     */
    private void cacheRecommendations(String key, List<Questions> questions, int seconds) {
        try {
            redisTemplate.opsForValue().set(key, questions, seconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.warn("缓存推荐结果失败: {}", e.getMessage());
        }
    }

    /**
     * 获取缓存的推荐结果
     */
    @SuppressWarnings("unchecked")
    private List<Questions> getCachedRecommendations(String key) {
        try {
            return (List<Questions>) redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            log.warn("获取缓存推荐结果失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 清除用户推荐缓存
     */
    public void clearUserRecommendCache(Long userId) {
        String cacheKey = "recommend:user:" + userId;
        redisTemplate.delete(cacheKey);
    }
}
